<template>
  <!-- SELECT 选择器 -->
  <el-select
    v-if="type === 'select'"
    v-model="internalValue"
    :placeholder="resolvedPlaceholder"
    :disabled="disabled"
    :multiple="multiple"
    clearable
    filterable
    :style="style"
    @change="handleValueChange"
  >
    <el-option
      v-for="option in mergedOptions"
      :key="option.value"
      :label="option.label"
      :value="option.value"
      :class="{ 'is-placeholder-option': option.isPlaceholder }"
    >
      <!-- 染色标签显示 -->
      <el-link v-if="option.tagType && color" :type="option.tagType">
        {{ option.label }}
      </el-link>
      <!-- 普通文本显示 -->
      <span v-else>{{ option.label }}</span>
    </el-option>
  </el-select>

  <!-- TREE-SELECT 树形选择器 -->
  <el-tree-select
    v-else-if="type === 'tree-select'"
    v-model="internalValue"
    :placeholder="resolvedPlaceholder"
    :disabled="disabled"
    :data="mergedOptions"
    :props="treeProps"
    :multiple="multiple"
    filterable
    @change="handleValueChange"
  />

  <!-- RADIO 单选框 -->
  <el-radio-group
    v-else-if="type === 'radio'"
    v-model="internalValue"
    :disabled="disabled"
    :style="style"
    @change="handleValueChange"
  >
    <el-radio
      v-for="option in mergedOptions"
      :key="option.value"
      :value="option.value"
    >
      {{ option.label }}
    </el-radio>
  </el-radio-group>

  <!-- RADIO BUTTON 单选按钮 -->
  <el-radio-group
    v-else-if="type === 'radio-button'"
    v-model="internalValue"
    :disabled="disabled"
    :style="style"
    @change="handleValueChange"
  >
    <el-radio-button
      v-for="option in mergedOptions"
      :key="option.value"
      :value="option.value"
    >
      {{ option.label }}
    </el-radio-button>
  </el-radio-group>

  <!-- CHECKBOX 复选框 -->
  <el-checkbox-group
    v-else-if="type === 'checkbox'"
    v-model="internalValue"
    :disabled="disabled"
    :style="style"
    @change="handleValueChange"
  >
    <el-checkbox
      v-for="option in mergedOptions"
      :key="option.value"
      :label="option.value"
    >
      {{ option.label }}
    </el-checkbox>
  </el-checkbox-group>

  <!-- CHECKBOX BUTTON 复选按钮 -->
  <el-checkbox-group
    v-else-if="type === 'checkbox-button'"
    v-model="internalValue"
    :disabled="disabled"
    :style="style"
    @change="handleValueChange"
  >
    <el-checkbox-button
      v-for="option in mergedOptions"
      :key="option.value"
      :label="option.value"
    >
      {{ option.label }}
    </el-checkbox-button>
  </el-checkbox-group>

  <!-- TRANSFER 穿梭框 -->
  <el-transfer
    v-else-if="type === 'transfer'"
    v-model="internalValue"
    :data="transferData"
    :props="transferProps"
    :titles="resolvedtransferTitles"
    :format="transferFormat"
    :disabled="disabled"
    :style="style"
    filterable
    @change="handleValueChange"
  />

  <!-- SWITCH 开关 -->
  <el-switch
    v-else-if="type === 'switch'"
    v-model="internalValue"
    inline-prompt
    :active-value="switchActiveValue"
    :inactive-value="switchInactiveValue"
    :active-text="resolvedswitchActiveText"
    :inactive-text="resolvedswitchInactiveText"
    :disabled="disabled"
    @change="handleValueChange"
  />
</template>
<script setup>
import { computed, ref, watch, onMounted, nextTick } from 'vue';
import { useDictStore } from '@/store';
import { smartTranslate as $t } from '@/lang';

const dictStore = useDictStore();
const props = defineProps({
  modelValue: [String, Number, Array, Boolean],
  code: {
    type: String,
    required: true,
  },
  type: {
    type: String,
    default: 'select',
    validator: (value) =>
      [
        'select',
        'radio',
        'radio-button',
        'checkbox',
        'checkbox-button',
        'tree-select',
        'transfer',
        'switch',
      ].includes(value),
  },
  multiple: Boolean,
  placeholder: {
    type: String,
    default: '',
  },
  disabled: Boolean,
  style: {
    type: Object,
    default: () => ({}),
  },
  perms: Boolean,
  color: Boolean,
  // 新增：标签映射配置
  labelMap: {
    type: Object,
    default: () => ({}),
  },
  // 新增：未知值的标签格式化函数
  unknownValueFormatter: {
    type: Function,
    default: (value) => `NaN: ${value}`,
  },
  // 新增：是否显示加载状态
  showLoading: {
    type: Boolean,
    default: false,
  },
  // 开关属性配置
  switchActiveValue: {
    type: [String, Number, Boolean],
    default: true,
  },
  switchInactiveValue: {
    type: [String, Number, Boolean],
    default: false,
  },
  switchActiveText: {
    type: String,
    default: '',
  },
  switchInactiveText: {
    type: String,
    default: '',
  },
  // 穿梭框配置
  transferTitles: {
    type: Array,
  },
  transferFormat: {
    type: Object,
    default: () => ({
      noChecked: '${total}',
      hasChecked: '${checked}/${total}',
    }),
  },
});

const emit = defineEmits(['update:modelValue', 'change', 'dict-loaded']);

// 字典选项数据
const dictOptions = ref([]);
// 加载状态
const loading = ref(false);
// 数据加载完成标志
const dictLoaded = ref(false);
// 内部值状态
const internalValue = ref();

const resolvedPlaceholder = computed(() => {
  return props.placeholder || $t('common.message.info.please_select');
});

const resolvedswitchActiveText = computed(() => {
  return props.switchActiveText || $t('common.message.info.open');
});

const resolvedtransferTitles = computed(() => {
  return (
    props.transferTitles || [
      $t('common.message.info.source'),
      $t('common.message.info.target'),
    ]
  );
});

// 计算是否为多选类型
const isMultipleType = computed(() => {
  return (
    ['checkbox', 'select', 'cascade', 'tree-select', 'transfer'].includes(
      props.type,
    ) && props.multiple
  );
});

// 树形选择器配置
const treeProps = computed(() => ({
  label: 'label',
  value: 'value',
  children: 'children',
}));

// 类型检查处理
const castValueToType = (value, targetType) => {
  if (value === null || value === undefined) return value;

  if (targetType === 'string') {
    return String(value);
  } else if (targetType === 'number') {
    const num = Number(value);
    // 如果转换结果是 NaN，则返回原始值，避免不必要的类型转换错误
    return isNaN(num) ? value : num;
  } else if (targetType === 'boolean') {
    // 特殊处理字符串 'true'/'false' 到布尔值的转换
    if (typeof value === 'string') {
      if (value.toLowerCase() === 'true') return true;
      if (value.toLowerCase() === 'false') return false;
    }
    return Boolean(value);
  }
  return value; // 如果目标类型不是原始类型，则返回原始值
};

// 值标准化处理
const normalizeValue = (value) => {
  if (isMultipleType.value) {
    if (value == null) return [];
    if (Array.isArray(value)) {
      // 对于多选类型，数组元素仍然转换为字符串，以确保与 Element Plus 组件的兼容性
      return value.map((v) => String(v));
    }
    if (typeof value === 'string') {
      return value.split(',').map((v) => String(v.trim()));
    }
    return [String(value)];
  }
  // 对于单选类型，保留原始值类型，null/undefined 转换为 undefined
  return value == null ? undefined : value;
};

// 获取值对应的标签
const getValueLabel = (value) => {
  // 将值转换为字符串
  const stringValue = String(value);

  // 1. 优先从 labelMap 中获取
  if (props.labelMap && typeof props.labelMap === 'object') {
    // 遍历 labelMap，将所有键转换为字符串进行比较
    for (const [key, label] of Object.entries(props.labelMap)) {
      if (String(key) === stringValue) {
        return label;
      }
    }
  }

  // 2. 从字典选项中查找
  const findInOptions = (options, targetValue) => {
    for (const option of options) {
      if (String(option.value) === targetValue) {
        return option.label;
      }
      // 递归查找子选项（用于级联和树形）
      if (option.children && Array.isArray(option.children)) {
        const childLabel = findInOptions(option.children, targetValue);
        if (childLabel) return childLabel;
      }
    }
    return null;
  };

  const label = findInOptions(dictOptions.value, stringValue);
  if (label) return label;

  // 3. 使用格式化函数处理未知值
  return props.unknownValueFormatter(value);
};

// 创建占位选项
const createPlaceholderOption = (value) => {
  return {
    value,
    label: getValueLabel(value),
    isPlaceholder: true, // 标记为占位选项
  };
};

// 获取当前值需要的占位选项
const getPlaceholderOptions = () => {
  const currentValue = normalizeValue(props.modelValue);
  const values = Array.isArray(currentValue) ? currentValue : [currentValue];
  const placeholders = [];

  values.forEach((value) => {
    if (value !== null && value !== undefined && value !== '') {
      // 将值转换为字符串进行比较
      const stringValue = String(value);
      // 检查是否在字典选项中存在
      const existsInDict = dictOptions.value.some(
        (option) => String(option.value) === stringValue,
      );
      if (!existsInDict) {
        placeholders.push(createPlaceholderOption(value));
      }
    }
  });

  return placeholders;
};

// 合并字典选项和占位选项
const mergedOptions = computed(() => {
  const placeholders = getPlaceholderOptions();
  const result = [...placeholders, ...dictOptions.value];

  const filtered = [];
  const processedValues = new Set();

  // 确定目标值类型：
  // 1. 如果 modelValue 是数组且有元素，则取第一个元素的类型。
  // 2. 如果 modelValue 非空且非数组，则取 modelValue 的类型。
  // 3. 如果 modelValue 为空，则尝试从 dictOptions 中推断，否则默认为字符串。
  let targetValueType;
  if (Array.isArray(props.modelValue) && props.modelValue.length > 0) {
    targetValueType = typeof props.modelValue[0];
  } else if (props.modelValue !== null && props.modelValue !== undefined) {
    targetValueType = typeof props.modelValue;
  } else if (dictOptions.value.length > 0) {
    targetValueType = typeof dictOptions.value[0].value;
  } else {
    targetValueType = 'string'; // 无法推断时的默认值
  }

  result.forEach((option) => {
    const originalValue = option.value;
    // 使用值及其原始类型作为 Set 的唯一键，以正确处理 '1' 和 1 这样的不同类型但相同内容的项
    const processedKey = `${typeof originalValue}-${originalValue}`;

    if (!processedValues.has(processedKey)) {
      let castedValue = originalValue;
      // 仅对单选组件进行类型转换，以匹配 internalValue 的类型
      // 对于多选组件，normalizeValue 已经确保 internalValue 元素为字符串，
      // 因此这里的 option.value 也应确保为字符串。
      if (!isMultipleType.value) {
        castedValue = castValueToType(originalValue, targetValueType);
      } else {
        // 确保多选组件的 option.value 也是字符串，与 internalValue 的元素类型保持一致
        castedValue = String(originalValue);
      }

      filtered.push({ ...option, value: castedValue });
      processedValues.add(processedKey);
    }
  });

  return filtered;
});

// 穿梭框数据转换
const transferData = computed(() =>
  mergedOptions.value.map((option) => ({
    key: option.value,
    label: option.label,
    disabled: option.disabled || false,
  })),
);

// 穿梭框属性配置
const transferProps = computed(() => ({
  key: 'key',
  label: 'label',
  disabled: 'disabled',
}));

// 获取字典数据
const loadDictionary = async () => {
  if (!props.code) return;

  try {
    loading.value = true;
    const data = await dictStore.getDictionary(props.code, props.perms);
    dictOptions.value = Array.isArray(data) ? data : [];
    dictLoaded.value = true;
    emit('dict-loaded', dictOptions.value);
  } catch (error) {
    console.error('dictionary loading failed:', error);
    dictOptions.value = [];
    dictLoaded.value = true;
  } finally {
    loading.value = false;
  }
};

// 值变化处理
const handleValueChange = (value) => {
  // 发出原始值，让父组件决定如何处理
  emit('update:modelValue', value);
  emit('change', value);
};

// 同步内部值 - 确保统一转换为字符串
const syncInternalValue = () => {
  internalValue.value = normalizeValue(props.modelValue);
};

// 监听 modelValue 变化
watch(() => props.modelValue, syncInternalValue, { immediate: true });

// 监听字典编码和权限变化
watch(
  [() => props.code, () => props.perms],
  () => {
    dictLoaded.value = false;
    loadDictionary();
  },
  { immediate: true },
);

// 监听 labelMap 变化
watch(
  () => props.labelMap,
  () => {
    // labelMap 变化时，强制更新显示
    nextTick(() => {
      syncInternalValue();
    });
  },
  { deep: true },
);

// 组件挂载时初始化
onMounted(() => {
  syncInternalValue();
});

// 暴露方法
defineExpose({
  reload: loadDictionary,
  refresh: loadDictionary,
  isLoading: () => loading.value,
  isDictLoaded: () => dictLoaded.value,
  getDictOptions: () => dictOptions.value,
  getMergedOptions: () => mergedOptions.value,
  getValueLabel,
});
</script>

<style scoped>
.is-placeholder-option {
  font-style: italic;
  opacity: 0.8;
}
</style>
